﻿using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using FTD2XX_NET;
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Threading;
using TMI85303.Utils;
using Serilog;
using CommunityToolkit.Mvvm.Messaging.Messages;
using CommunityToolkit.Mvvm.Messaging;
using TMI85303.UI.Messages;
using System.Windows.Input;
using TMI85303.UI.View;
using System.Runtime.Intrinsics.Arm;
using System.Reflection;
using System.Text;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
using static TMI85303.Utils.ReadWrite;
using System.Collections.ObjectModel;

namespace TMI85303.UI.ViewModels
{
    public partial class MainWindowVM : ObservableRecipient
    {
        public ObservableCollection<FtDeviceListInforNode> AllConnectAddr { get; set; } = new();

        [ObservableProperty]
        private int selectConnectAddrIndex = -1;

        [ObservableProperty]
        private DateTime? currentDataTime = null;
        private readonly DispatcherTimer updateTime = new();

        public static bool MTPchackFailed { get; set; } = false;

        [ObservableProperty]
        private bool outlineFlag;

        public static bool OutlineGlobalFlag { get; set; } = false;

        [ObservableProperty]
        private bool enableRefreshDev = true;

        [ObservableProperty]
        private bool enableSelectDev = false;

        [ObservableProperty]
        private bool enableConnectDev = false;

        [ObservableProperty]
        private bool connectedOk = false;

        [ObservableProperty]
        private bool enableControlRegion = false;

        [ObservableProperty]
        private bool enableTabControlRegion = false;

        [ObservableProperty]
        private bool continueReadSpeedCheck = false;

        [ObservableProperty]
        private string? startButtonContent = "Start";

        [ObservableProperty]
        private int dutyCycleValue;
        public static int MainDutyCycleValue;

        private int dutyCycleValueMax = MainDutyCycleValueMax;
        public int DutyCycleValueMax
        {
            get => dutyCycleValueMax;
        }
        public static int MainDutyCycleValueMax = 511;


        private int dutyCycleValueMin = MainDutyCycleValueMin;
        public int DutyCycleValueMin
        {
            get => dutyCycleValueMin;
        }
        public static int MainDutyCycleValueMin = 0;


        private bool isRunn = false;
        public bool IsRunn
        {
            get => isRunn;
            set 
            {
                SetProperty(ref isRunn, value);
                MainIsRunn = value;
            }
        }
        public static bool  MainIsRunn = false;


        [ObservableProperty]
        private double dutyCycleRatioValue;

        [ObservableProperty]
        private double appliedDuty=double.MinValue;

        [ObservableProperty]
        private int speedShow = int.MinValue;

        private readonly DispatcherTimer updateSpeedTime = new();

        [ObservableProperty]
        private string? continuousReadContent = "Continue";

        [ObservableProperty]
        private string rPMInfo = "RPM = 0\r\nFG = 0 Hz\r\nErev = 0Hz";
        [ObservableProperty]
        private bool rPMInfoVisible = false;

        [ObservableProperty]
        private bool ignoreChipAdjustCheck = false;

        private uint I2CClock_KHz = 400;

        private readonly DispatcherTimer CheckConnectTime = new();


        public MainWindowVM()
        {
            InitUpdateCurrentTime();

            OutlineFlag = false;
            DutyCycleValue = 103;

            updateSpeedTime.Interval = TimeSpan.FromMilliseconds(100);
            updateSpeedTime.Tick += (s, e) => UpdateSpeed();

            CheckConnectTime.Interval = TimeSpan.FromMinutes(3);
            CheckConnectTime.Tick += (s, e) => OnCheckConnect();

            WeakReferenceMessenger.Default.Register<RPMInfoVisibleMesg, int>(this, (int)MesgToken.MainWindowToken, (s, e) => RPMInfoVisible = e.Visible);
            WeakReferenceMessenger.Default.Register<UpdateRPMInfoMesg, int>(this, (int)MesgToken.MainWindowToken, (s, e) => RPMInfo = e.Info);
            WeakReferenceMessenger.Default.Register<UpdateI2CClock, int>(this, (int)MesgToken.MainWindowToken, (s, e) => I2CClock_KHz = e.NewClockSpeed);
        }

        private void OnCheckConnect()
        {
            if (ReadWrite.ConnectedOk && !ReadWrite.IsI2COk())
            {
                CheckConnectTime.Stop();
                WeakReferenceMessenger.Default.Send<WriteFileMTPDataConfig, int>(new(), (int)MesgToken.MTP_DATA);
                if (ReadWrite.DisConnectDev())
                {
                    ConnectedOk = true;
                    ConnectDev();
                }
                else
                {
                    Log.Error("当前I2C通讯异常中断，请检查芯片电源及I2C连接！");
                }

            }
        }

        private void InitUpdateCurrentTime()
        {
            updateTime.Interval = TimeSpan.FromSeconds(1);
            updateTime.Tick += (s, e) => CurrentDataTime = DateTime.Now;
            updateTime.Start();
        }

        partial void OnOutlineFlagChanged(bool value)
        {
            OutlineGlobalFlag = value;
            if (!ConnectedOk)
            {
                EnableControlRegion = value;
                EnableTabControlRegion = value;
            }
        }

        [RelayCommand]
        private void RefeshExistDevs()
        {
            SelectConnectAddrIndex = -1;
            AllConnectAddr.Clear();

            if (ReadWrite.SearchDevList(out var listDevs))
            {
                foreach (var addr in listDevs)
                {
                    AllConnectAddr.Add(addr);
                }

                if (AllConnectAddr.Count > 0)
                {
                    SelectConnectAddrIndex = 0;
                }

                EnableSelectDev = true;
                EnableConnectDev = true;
            }
            else
            {
                Log.Information("No device found!\r\n" +
    "Please check whether the device is connected? If not, please connect the device and open the software again!\r\n");
            }
        }

        partial void OnSelectConnectAddrIndexChanged(int value) => EnableConnectDev = value != -1;

        partial void OnConnectedOkChanged(bool value)
        {
            if (value)
            {
                EnableRefreshDev = false;
                EnableSelectDev = false;
            }
            else
            {
                EnableRefreshDev = true;
                EnableSelectDev = true;
            }
        }

        [RelayCommand]
        private void ConnectDev()
        {
            if (ConnectedOk) // 连接
            {
                if (AllConnectAddr.Count <= 0 || SelectConnectAddrIndex == -1)
                {
                    MessageBox.Show("Please select the desired interface!\r\n");
                    ConnectedOk = false;
                    return;
                }

                if (ReadWrite.ConnectDev(AllConnectAddr[SelectConnectAddrIndex].Locid, I2CClock_KHz))
                {
                    if (ReadWrite.IsI2COkMutil())
                    {
                        Log.Information(" Device successfully connected\r\n");
                        CheckConnectTime.Start();

                        ReadWrite.WriteReg(165, 0, 2);//停止电机
                        if (!IgnoreChipAdjustCheck)
                        {
                            Reg28_31TrimCheck();
                        }
                    }
                    else
                    {
                        Log.Error("I2C通讯异常，请检查电源及连线！");
                        if (ReadWrite.DisConnectDev())
                        {
                            ConnectedOk = false;
                            return;
                        }
                    }

                    EnableControlRegion = true;
                    EnableTabControlRegion = true;
                    
                    EnableRefreshDev = false;
                    EnableSelectDev = false;
                }
                else
                {
                    MessageBox.Show("Device connection failed!\r\n" +
                    "Please check whether the device is connected? If not, please connect the device and open the software again!\r\n"
                    , "", MessageBoxButton.OK, MessageBoxImage.Error);

                    ConnectedOk = false;
                }

            }
            else //断开
            {
                if (ReadWrite.DisConnectDev())
                {
                    EnableControlRegion = false;
                    EnableTabControlRegion = false;

                    EnableRefreshDev = true;
                    EnableSelectDev = true;

                    Log.Information(" Device disconnect");
                    if (IsRunn)
                    {
                        StartButtonContent = "Start";
                    }
                }
                else
                {
                    ConnectedOk = true;
                }

            }
        }

        partial void OnDutyCycleValueChanged(int value)
        {
            MainDutyCycleValue = value;
            DutyCycleRatioValue = Math.Round((float)value * 100 / 511,1);
            if (IsRunn)
            {
                Log.Debug(" PWM Duty Cycle " + DutyCycleRatioValue + "%");
                ReadWrite.WriteReg(165, value, 2);
            }
            WeakReferenceMessenger.Default.Send<RefreshSpeedCurveMesg, int>(new(), (int)MesgToken.RegVMToken);
        }

        [RelayCommand]
        private void StartStopRotate()
        {
            if (IsRunn)
            {
                StartButtonContent = "Stop";
                Log.Information(" PWM Duty Cycle " + DutyCycleRatioValue + "%");
                ReadWrite.WriteReg(165, DutyCycleValue, 2);
            }
            else
            {
                StartButtonContent = "Start";

                Log.Information(" PWM Duty Cycle 0.0%");
                ReadWrite.WriteReg(165, 0, 2);
            }
        }



        [RelayCommand]
        private void UpdateSpeed()
        {
            int speedNumToAve = 10;
            int[] speedPrevValues = new int[checked(speedNumToAve + 1)];
            int speedBufferCount = 0;
            int speedDataTem = SpeedShow;
            

            //int speedCode = ReadWrite.ReadRegNoLog(140, 2);
            //if(speedCode == 0)
            //{
            //    Log.Information("a");
            //}
            if (!ReadWrite.TryReadRegNoLog(140, 2, out int speedCode))
            {
                Log.Information("fail");
            }

            if (speedBufferCount <= speedNumToAve)
            {
                speedBufferCount++;
            }
            int num3 = speedNumToAve - 2;
            for (int i = 0; i <= num3; i++)
            {
                speedPrevValues[i] = speedPrevValues[i + 1];
            }
            speedPrevValues[speedNumToAve - 1] = speedCode;
            int num4 = speedNumToAve - 1;
            for (int j = 0; j <= num4; j++)
            {
                speedDataTem += speedPrevValues[j];
            }
            speedDataTem = ((speedBufferCount < speedNumToAve) ? speedCode : ((int)Math.Round((double)speedDataTem / (double)speedNumToAve)));
            SpeedShow = speedDataTem;
            //SpeedPlotWin.Logger?.Add(speedDataTem);
            //WeakReferenceMessenger.Default.Send<SpeedPlotClosedMesg, int>(new(speedDataTem), (int)MesgToken.SpeedPlotWinToken);
            speedPlotWin?.UpdateData(speedDataTem);
            AppliedDuty = Math.Round(100.0 * (double)ReadWrite.ReadReg(128, 2) / 511.0,1);
        }


        [RelayCommand]
        private void ContinuousReadMTP()
        {
            if (ContinueReadSpeedCheck)
            {
                ContinuousReadContent = "Stop";
                updateSpeedTime.Start();
                WeakReferenceMessenger.Default.Send<SpeedPlotPointCatch, int>(new(false), (int)MesgToken.SpeedPlotWinToken);

            }
            else
            {
                ContinuousReadContent = "Continue";
                updateSpeedTime.Stop();
                SpeedShow = int.MinValue;
                AppliedDuty = double.MinValue;
                WeakReferenceMessenger.Default.Send<SpeedPlotPointCatch, int>(new(true), (int)MesgToken.SpeedPlotWinToken);

            }
        }

        private SpeedPlotWin? speedPlotWin = null;
        [RelayCommand]
        private void OpenPlot()
        {
            var existingWindow = Application.Current.Windows.Cast<System.Windows.Window>().FirstOrDefault(window => window is SpeedPlotWin) as SpeedPlotWin;
            if (existingWindow != null)
            {
                speedPlotWin = existingWindow;
                speedPlotWin.Focus();
            }
            else
            {
                speedPlotWin = new SpeedPlotWin();
                speedPlotWin.Show();

                if (!ContinueReadSpeedCheck)
                {
                    ContinueReadSpeedCheck = true;
                    ContinuousReadMTP();
                }
            }
        }

        private void Reg28_31TrimCheck()
        {
            int readRes28 = ReadWrite.ReadReg(28, 2);
            int readRes31 = ReadWrite.ReadReg(31, 2);
            if((readRes28 == 0 && readRes31 == 0) || (readRes28 == 0xFFFF && readRes31 == 0xFFFF))
            {
                MessageBox.Show("未读取到芯片修调数据，\r\n芯片为空片！", "芯片修调检测", MessageBoxButton.OK, MessageBoxImage.Warning);
            }
        }
    }
}
